<?php
/**
 * ***********************************************************************************
 * 咨询鲤 PC端知识店铺-考试相关
 * 
 * @author Mr.RJH
 * @date 2025-09-10
 * @email<15213026209@163.com>
 * ***********************************************************************************
 */
namespace app\controller;

use app\BaseController;

use think\facade\Db;
use app\model\merchant\ConfigModel;
use app\model\product\ZxlKnowStoreProductModel;
use app\model\product\ZxlKnowStoreProductAttrModel;
use app\model\product\ZxlKnowStoreCategoryModel;
use app\model\product\ZxlKnowStoreExamSetModel;
use app\model\product\ZxlKnowStoreExamContentModel;

use app\model\user\ZxlKnowStoreLikeLogModel;
use app\model\user\ZxlKnowStoreCollectModel;
use app\model\user\ZxlKnowStorePowerModel;

use app\model\question\ZxlKnowStoreQuestionPracticeModel;
use app\model\question\ZxlKnowStoreQuestionPracticeDetailModel;
use app\model\question\ZxlKnowStoreQuestionModel;
use app\model\question\ZxlKnowStoreQuestionMaterialModel;

use app\service\ProductService;

class Exam extends BaseController
{
    /**
     * 考试列表
     * 
     * @return mixed
     */
    public function index()
    {
        if ($this->request->isPost()) {

            $limit = $this->request->param('limit');
            $page = $this->request->param('page',1);
            $cate_id = $this->request->param('category_id','');
            
            $m_id = $this->request->m_id;
            try {
                //查询条件
                $productService = new ProductService($m_id);
                $list = $productService->get_product_list(10, $limit, $page, $cate_id);

                foreach ($list['data'] as &$v) {
                    // 考试设置
                    $exam_set = ZxlKnowStoreExamSetModel::where('product_id', $v['id'])->field('exam_time_type,exam_start_time,exam_end_time,answer_time')->find();

                    $exam_set['status'] = 1; // 进行中
                    if ($exam_set['exam_time_type'] == 1) {
                        if (time() < $exam_set['exam_start_time'] && $exam_set['exam_end_time'] > time()) {
                            $exam_set['status'] = 0; // 未开始
                        } else if (time() > $exam_set['exam_end_time']) {
                            $exam_set['status'] = 2; // 已结束
                        }
                    }
                    $v['exam_set'] = $exam_set;
                    $v['question_num'] = ZxlKnowStoreExamContentModel::get_question_num($v['id']);
                }
            } catch (\Exception $e) {
                return json(['code' => 1,'msg' => $e->getMessage()]);
            }
            return json(['code' => 0,'msg' => 'SUCCESS','count' => $list['total'],'data' => $list['data']]);
        }
        // 获取分类
        $first_category = ZxlKnowStoreCategoryModel::first_category($this->request->m_id, 10);
        $second_category = [];
        if ($first_category) {
            $second_category = ZxlKnowStoreCategoryModel::second_category($this->request->m_id, $first_category[0]['id']);
        }
        $this->assign('second_category', $second_category);
        return $this->fetch();
    }

    /**
     * 考试详情
     * 
     * @return mixed
     */
    public function detail()
    {
        $id = $this->request->param('id');
        $info = ZxlKnowStoreProductModel::getInfo($this->request->m_id, $id);
        if (!$info) {
            return redirect('/error/http404');
        } else {
            $info->visit_num += 1; // 增加访问量
            $info->save();

            $info['head_imgs'] = '/static/images/exam.png';
            if ($info['tags']) {
                $info['tags'] = json_decode($info['tags'], true);
            }
            
            $info['question_num'] = ZxlKnowStoreExamContentModel::get_question_num($info['id']);
            // 是否收藏
            $info['is_favorites'] = 0;
            $favorites = ZxlKnowStoreCollectModel::where(['user_id' => $this->user_id, 'product_id' => $info['id']])->find();
            if ($favorites) {
                $info['is_favorites'] = 1;
            }

            // 考试设置
            $set = ZxlKnowStoreExamSetModel::where('product_id', $info['id'])->find();
            if ($set['exam_start_time']) {
                $set['exam_start_time'] = date('Y-m-d H:i', $set['exam_start_time']);
                $set['exam_end_time'] = date('Y-m-d H:i', $set['exam_end_time']);
            }
            $info['set'] = $set;

            // 是否购买
            $info['is_buy'] = ZxlKnowStorePowerModel::getPowerDetail($info['id'], $this->user_id);
        }
        // 购课须知
        $notice = ConfigModel::getConfigValue('notice')[1];

        $productService = new ProductService($this->request->m_id);
        // 相关考试
        $related_list = $productService->rand_recommend_product(4, 10);
        
        $this->assign('info', $info);
        $this->assign('notice', $notice);
        $this->assign('related_list', $related_list);
        return $this->fetch();
    }

    /**
     * 考试记录
     * 
     * @return json
     */
    public function get_exam_log()
    {
        if ($this->request->isPost()) {

            $limit = $this->request->param('limit');
            $page = $this->request->param('page', 1);
            $product_id = $this->request->param('product_id', '');
            $is_my = $this->request->param('is_my', 0); // 是否我的 0否 1是
            try {
                
                $query = ZxlKnowStoreQuestionPracticeModel::with(['user'=>function($q){
                    $q->field('id, nickname_two, avatar');
                }])
                ->where(['practice_type' => 'professional','target_id' => $product_id])
                ->where('sub_time', '>', 0);
                if($is_my == 1) {
                    $query->where('user_id', $this->user_id);
                }
                $list = $query->field('id, user_id, sub_time, status, create_time, score, correct_rate, like, target_id')->order('sub_time', 'desc')->paginate($limit,false,['page'=>$page])->toArray();
                foreach($list['data'] as &$v){
                    $v['show_time'] = show_time_format(bcsub($v['sub_time'], $v['create_time']));
                    $v['sub_time'] = tranTimes($v['sub_time']);

                    // 当前用户是否点赞
                    $v['is_like'] = ZxlKnowStoreLikeLogModel::isLike($v['id'], $this->user_id, 3);
                    
                    $v['correct_rate'] .= '%'; // 正确率
                    if ($v['user_id'] == $this->user_id && $v['status'] == 0){
                        $v['score'] = -1;
                        $v['correct_rate'] = '--';
                        $v['extra'] = ZxlKnowStoreQuestionPracticeModel::STATUSSEXAMTR[$v['status']];
                    }           
                    $exam = ZxlKnowStoreExamSetModel::where('product_id', ZxlKnowStoreProductModel::getMainProductId($v['target_id']))->field('product_id, score_show, topic_show, answer_show')->find();
                    if($exam['score_show'] == 0){
                        $v['score'] = -1;
                        $v['extra'] = '--';
                        $v['correct_rate'] = '--';
                    }
                    $v['product_name'] = ZxlKnowStoreProductModel::where('id', $product_id)->value('name');
                }
            } catch (\Exception $e) {
                return json(['code' => 1,'msg' => $e->getMessage()]);
            }
            return json(['code' => 0,'msg' => 'SUCCESS','count' => $list['total'],'data' => $list['data']]);
        }
    }

    /**
     * 验证是否满足可考试
     * 
     * @return json
     */
    public function verify_is_practice()
    {
        if ($this->request->isPost()) {
            try {
                $product_id = $this->request->param('product_id');
                // 考试设置
                $set = ZxlKnowStoreExamSetModel::where('product_id', $product_id)->find();
                if($set['exam_num'] > 0) {
                    // 已考试次数
                    $count = $this->get_practice_count($product_id);
                    if($count >= $set['exam_num']) {
                        throw new \Exception('只可考试'.$set['exam_num'].'次');
                    }
                }
                if($set['retake_limit'] == 1){
                    $practice = $this->get_latest_sub_practice($product_id);
                    if($practice && $practice['status'] != 3) {
                        throw new \Exception('你的最新考试还未批阅，需批阅后才能重考');
                    }
                }
                // 存在考试间隔
                if($set['retake_interval'] > 0){
                    // 存在考试间隔时间
                    $practice = $this->get_latest_sub_practice($product_id);
                    if ($practice) {
                        if(time() < $practice['sub_time'] + $set['retake_interval']*60) {
                            throw new \Exception('当前考试间隔需要：'.$set['retake_interval'].'分钟');
                        }
                    }
                }

                return json(['code' => 0, 'msg' => 'SUCCESS']);
            } catch (\Exception $e) {
                return json(['code' => 1,'msg' => $e->getMessage()]);
            }
        }
        
    }

    /**
     * 获取当前考试已完成次数
     * 
     * @param int $product_id
     * @return int
     */
    private function get_practice_count($product_id)
    {
        $where = function($q)use($product_id){
            $q->where('user_id', $this->user_id);
            $q->where('target_id', $product_id);
            $q->where('sub_time', '>', 0);
            $q->where('status', '>', 0);
            $q->where('practice_type', 'professional'); // 考试
        };
        $count = ZxlKnowStoreQuestionPracticeModel::where($where)->count();
        return $count;
    }

    /**
     * 获取最新提交考试
     * 
     * @param int $product_id
     * @return int
     */
    private function get_latest_sub_practice($product_id)
    {
        $where = function($q)use($product_id){
            $q->where('user_id', $this->user_id);
            $q->where('target_id', $product_id);
            $q->where('sub_time', '>', 0);
            $q->where('status', '>', 0);
            $q->where('practice_type', 'professional'); // 考试
        };
        $practice = ZxlKnowStoreQuestionPracticeModel::where($where)->order('sub_time', 'desc')->find();
        return $practice;
    }

    /**
     * 考试做题
     * 
     * @return mixed
     */
    public function practice()
    {
        $product_id = $this->request->param('product_id');
        // 是否购买考试
        $is_buy = ZxlKnowStorePowerModel::getPowerDetail($product_id, $this->user_id);
        
        $info = ZxlKnowStoreProductModel::getInfo($this->request->m_id, $product_id, $is_buy);
        if (!$info) {
            return redirect('/error/http404');
        }
        $question_list = [];
        // 获取考试内容
        $question_ids = ZxlKnowStoreExamContentModel::where(['product_id' => ZxlKnowStoreProductModel::getMainProductId($product_id), 'p_id' => 0])->order(['sort' => 'desc','id' => 'asc'])->column('question_id');
        $total_question = count($question_ids);
        $question_ids = ZxlKnowStoreQuestionModel::filterMaterialQuestion($question_ids); // 去重

        // 插入做题记录
        $info['practice_id'] = ZxlKnowStoreQuestionPracticeModel::save_practice($this->user_id, $this->request->m_id, $info['id'], $product_id, $total_question);
        
        $field = 'id, m_id, question, options, type, difficulty, material_id, chapter_id, answer, analyze, lib_id';
        $question_list = ZxlKnowStoreQuestionModel::whereIn('id', $question_ids)->field($field)->orderRaw('FIELD(id, ' . implode(',', $question_ids) . ')')->select()->toArray();
        foreach ($question_list as &$v) {
            if (!$v) {
                continue;
            }
            if ($v['material_id'] > 0) {
                // 材料题
                $v['type'] = 9;
                $v['type_name'] = ZxlKnowStoreQuestionModel::get_type($v['type']);
                $material = ZxlKnowStoreQuestionMaterialModel::find($v['material_id']);
                $v['material'] = $material['content'];
                $v['question_voice'] = $material['question_voice'];
                // 查询当前材料的所有问题根据考试内容查询
                $questions = ZxlKnowStoreQuestionModel::where("material_id", $v['material_id'])->field($field)->select()->toArray();
                foreach ($questions as &$val) {
                    $val['options'] = json_decode($val['options'], true);
                    $val['type_name'] = ZxlKnowStoreQuestionModel::get_type($val['type']);
                    // 获取做题详情
                    $val['practice_detail'] = ZxlKnowStoreQuestionPracticeDetailModel::get_user_practice_detail($info['practice_id'], $this->user_id, $val['id']);
                }
                $v['children'] = $questions;
            }
            // 获取做题详情
            $v['practice_detail'] = ZxlKnowStoreQuestionPracticeDetailModel::get_user_practice_detail($info['practice_id'], $this->user_id, $v['id']);
            $v['options'] = json_decode($v['options'], true);
            
            $v['type_name'] = ZxlKnowStoreQuestionModel::get_type($v['type']);
        }
        
        $this->assign('question_list', $question_list);
        $this->assign('info', $info);
        return $this->fetch();
    }

    
    /**
     * 提交考试
     * 
     * @return josn
     */
    public function practice_submit()
    {
        if ($this->request->isPost()) {
            Db::startTrans(); // 开启事务回滚
            try {
                $post = $this->request->post();
                
                $question_ids = ZxlKnowStoreExamContentModel::where(['product_id' => $post['id'], 'p_id' => 0])->column('question_id');
                $question_list = ZxlKnowStoreQuestionModel::whereIn('id', $question_ids)->select()->toArray();
                if ($post['exit'] == 0) {
                    if (count($post['answer']) < count($question_list)) {
                        Db::rollback();
                        return json(['code' => 1,'msg' => '你有未完成的答题，请完成后再交卷']);
                    }
                }
                // 更新做题记录
                $practice = ZxlKnowStoreQuestionPracticeModel::find($post['practice_id']);
                if ($practice) {
                    // 记录用户答题详情
                    $total_score = 0;
                    foreach ($post['answer'] as $key => $v) {
                        if ($v) {
                            if (!is_array($v)) {
                                $v = [$v];
                            }
                            // 记录答题详情
                            $practice_detail = ZxlKnowStoreQuestionPracticeDetailModel::addLog($key, $v, $practice);
                            if ($practice_detail->is_correct == 1) { // 回答正确记录分数
                                $total_score += $practice_detail->score;
                            }
                        }
                        
                    }
                    
                    // 此次训练正确数量
                    $rightCount = ZxlKnowStoreQuestionPracticeDetailModel::where(["practice_id" => $practice['id'], "is_correct" => 1])->count();
                    //计算正确率 n%
                    $rate = 0;
                    $totalNum = ZxlKnowStoreQuestionPracticeDetailModel::where(["practice_id" => $practice['id']])->count();
                    if($practice->total_question > $totalNum) $totalNum = $practice->total_question;
                    
                    if($rightCount > 0 && $totalNum > 0){
                        $rate = bcmul(bcdiv($rightCount, $totalNum, 4), 100, 2);
                    }
                    if ($post['exit'] == 0) {
                        // 交卷
                        $practice->score = $total_score;
                        $practice->correct_rate = $rate;
                        $practice->update_time = time();
                        $practice->sub_time = time();
                        $practice->status = 1;
                        $practice->save();
                    }
                }
                
                Db::commit();
                return json(['code' => 0, 'msg' => '提交成功']);
            } catch (\Exception $e) {
                Db::rollback();
                return json(['code' => 1,'msg' => $e->getMessage()]);
            }
        }
    }

    /**
     * 练习详情
     * 
     * @return mixed
     */
    public function practice_detail()
    {
        if ($this->request->isPost()) {
            
            $m_id = $this->request->m_id;
            $product_id = $this->request->param('product_id');
            try {
                // 最新做题记录
                $practice = $this->get_latest_practice($product_id);
                if ($practice) {
                    // 获取练题详情
                    $practice_detail = ZxlKnowStoreQuestionPracticeDetailModel::where(['practice_id' => $practice['id']])->select()->toArray();
                    if ($practice['status'] == 0) { // 未提交
                        $grade['name'] = '完成度';
                        $grade['value'] = round((count($practice_detail) / $practice['total_question']) * 100, 2);
                    } else {
                        $grade['name'] = '本次得分';
                        $grade['value'] = $practice['score'];
                    }
                } else {
                    $grade['name'] = '完成度';
                    $grade['value'] = 0;
                }
                
                return json(['code' => 0,'msg' => 'SUCCESS', 'data' => $grade['value'], 'name' => $grade['name']]);
            } catch (\Exception $e) {
                return json(['code' => 1,'msg' => $e->getMessage()]);
            }
        }

        $product_id = $this->request->param('product_id');
        // 是否购买考试
        $is_buy = ZxlKnowStorePowerModel::getPowerDetail($product_id, $this->user_id);
        
        $info = ZxlKnowStoreProductModel::getInfo($this->request->m_id, $product_id, $is_buy);
        if (!$info) {
            return redirect('/error/http404');
        } else {
            $info['question_num'] = ZxlKnowStoreExamContentModel::get_question_num($info['id']);
            $info['total_score'] = ZxlKnowStoreExamContentModel::where('product_id', $info['id'])->sum('score');
            $set = ZxlKnowStoreExamSetModel::where('product_id', $info['id'])->find();
            if ($set) {
                $set['status'] = 1; // 进行中
                if ($set['exam_time_type'] == 1) {
                    if (time() < $set['exam_start_time'] && $set['exam_end_time'] > time()) {
                        $set['status'] = 0; // 未开始
                    } else if (time() > $set['exam_end_time']) {
                        $set['status'] = 2; // 已结束
                    }
                }
                if ($set['exam_start_time']) {
                    $set['exam_start_time'] = date('Y-m-d H:i', $set['exam_start_time']);
                    $set['exam_end_time'] = date('Y-m-d H:i', $set['exam_end_time']);
                }
                
            }
            $info['set'] = $set;

            // 最新做题记录
            $practice = $this->get_latest_practice($product_id);
            $done_practice_count = 0; // 已做题数
            if ($practice) {
                if ($practice['status'] == 0) {
                    $practice['sub_time'] = ZxlKnowStoreQuestionPracticeDetailModel::where(['practice_id' => $practice['id']])->order('create_time desc')->value('create_time');
                }
                $show_time = bcsub($practice['sub_time'], $practice['create_time']);
                $practice['show_time'] = $show_time > 0 ? show_time_format($show_time) : '--';
                // 已做题数
                $done_practice_count = ZxlKnowStoreQuestionPracticeDetailModel::where(['practice_id' => $practice['id']])->count();

                // 获取排行榜
                $current_rank = 0;
                $rank_list = $this->get_exam_rank($product_id);
                foreach ($rank_list as $key => $v) {
                    if ($v['user_id'] == $practice['user_id'] && $v['max_score'] == $practice['score']) {
                        $current_rank = $key + 1;
                        break;
                    }
                }
                $practice['current_rank'] = $current_rank;
            }
            $info['practice'] = $practice;
            $info['done_practice_count'] = $done_practice_count;
        }
        
        $this->assign('info', $info);
        return $this->fetch();
    }

    /**
     * 获取最新练题记录
     * 
     * @return array
     */
    private function get_latest_practice($product_id)
    {
        $m_id = $this->request->m_id;
        $where = function($q)use($m_id,$product_id){
            $q->where('m_id', $m_id);
            $q->where('target_id', $product_id);
            $q->where('user_id', $this->user_id);
            $q->where('practice_type', 'professional'); // 考试
        };
        // 最新做题记录
        $practice = ZxlKnowStoreQuestionPracticeModel::where($where)->order('create_time desc')->find();

        return $practice;
    }

    /**
     * 获取考试排行榜
     * 
     * @return array
     */
    private function get_exam_rank($product_id)
    {
        $m_id = $this->request->m_id;
        $where = function($q)use($m_id,$product_id){
            $q->where('m_id', $m_id);
            $q->where('target_id', $product_id);
            $q->where('status', '>', 0);
            $q->where('practice_type', 'professional'); // 考试
        };
        $subQuery = ZxlKnowStoreQuestionPracticeModel::where($where)
            ->order(['score' => 'desc', 'sub_time' => 'desc'])
            ->field('user_id, MAX(score) as max_score, sub_time')
            ->group('user_id')
            ->buildSql();

        $list = ZxlKnowStoreQuestionPracticeModel::with(['user' => function($q) {
            $q->field('id, nickname_two, avatar');
        }])->table($subQuery . ' tmp')->order(['max_score' => 'desc', 'sub_time' => 'desc'])->limit(15)->select()->toArray();
        
        return $list;
    }

    /**
     * 练习排行榜
     * 
     * @return mixed
     */
    public function practice_rank()
    {
        $product_id = $this->request->param('product_id');
        $info = ZxlKnowStoreProductModel::where(['m_id' => $this->request->m_id, 'id' => $product_id, 'is_delete' => 0])->find();
        if (!$info) {
            return redirect('/error/http404');
        }
        $list = $this->get_exam_rank($product_id);
        
        $this->assign('list', $list);
        $this->assign('info', $info);
        return $this->fetch();
    }

}